package com.rp.data.tcp_ws.server_ws;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Slf4j
@Component
public class NettyServerWs {

    private static NettyServerWs nettyServerWs;

    @PostConstruct
    public void init() {
        nettyServerWs = this;
    }

    private static class SingletionNettyServer {
        static final NettyServerWs instance = new NettyServerWs();
    }

    public static NettyServerWs getInstance() {
        return SingletionNettyServer.instance;
    }

    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private ServerBootstrap bootstrap;
    private Channel channel;

    public NettyServerWs() {
        // TODO Auto-generated method stub
        // EventLoopGroup是用来处理IO操作的多线程事件循环器
        // 负责接收客户端连接线程
        bossGroup = new NioEventLoopGroup();
        // 负责处理客户端i/o事件、task任务、监听任务组
        workerGroup = new NioEventLoopGroup();
        // 启动 NIO 服务的辅助启动类
        bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workerGroup);
        // 配置 Channel
        bootstrap.channel(NioServerSocketChannel.class);
        bootstrap.childHandler(new ServerIniterHandlerWs());
        // BACKLOG用于构造服务端套接字ServerSocket对象，
        // 标识当服务器请求处理线程全满时，用于临时存放已完成三次握手的请求的队列的最大长度
        bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
        // 是否启用心跳保活机制
        bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
    }

    public void start(int port){
        try {
            // 绑定服务端口监听
            channel = bootstrap.bind(port).sync().channel();
            log.info("成功开启端口:" + port);
            // 服务器关闭监听
            /*
             * channel.closeFuture().sync()实际是如何工作:
             * channel.closeFuture()不做任何操作，只是简单的返回channel对象中的closeFuture对象，对于每个Channel对象，
             * 都会有唯一的一个CloseFuture，用来表示关闭的Future，
             * 所有执行channel.closeFuture().sync()就是执行的CloseFuturn的sync方法，从上面的解释可以知道，
             * 这步是会将当前线程阻塞在CloseFuture上
             */
            channel.closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 关闭事件流组
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
